package cn.kone.system.service.impl;


import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.kone.base.exception.BusinessException;
import cn.kone.system.domain.Logininfo;
import cn.kone.system.domain.Menu;
import cn.kone.system.dto.LoginDTO;
import cn.kone.system.jwt.JwtUtil;
import cn.kone.system.jwt.Payload;
import cn.kone.system.mapper.LogininfoMapper;
import cn.kone.system.query.LogininfoQuery;
import cn.kone.system.service.ILogininfoService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务实现类: 登录信息Logininfo
 */
@Service
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class LogininfoServiceImpl implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Override
    public List<Logininfo> findAll() {
        return logininfoMapper.findAll();
    }

    @Override
    public Logininfo findOne(Long id) {
        return logininfoMapper.findOne(id);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        //删除角色
        logininfoMapper.delete(id);
    }

    @Override
    @Transactional
    public void add(Logininfo logininfo) {
        //添加角色信息
        logininfoMapper.add(logininfo); //自增id
    }

    @Override
    @Transactional
    public void update(Logininfo logininfo) {
        logininfoMapper.update(logininfo);
    }

    @Override
    public void patchDelete(Long[] ids) {
        logininfoMapper.patchDelete(ids);
    }

    @Override
    public PageInfo<Logininfo> queryPage(LogininfoQuery logininfoQuery) {
        //1.开启分页
        PageHelper.startPage(logininfoQuery.getCurrentPage(), logininfoQuery.getPageSize());
        //a.查询总数量 - count()
        //b.会根据方言 mysql 自动实现分页查询,如果是mysql就会使用limit查询
        //c.自动计算limit的第一个参数: (currentPage-1)*pageSize
        //2.操作数据库
        List<Logininfo> data = logininfoMapper.queryPage(logininfoQuery);
        return new PageInfo<>(data);
    }

    //后台登陆
    @Override
    public String accountLogin(LoginDTO loginDTO) {
        String account = loginDTO.getAccount();
        String password = loginDTO.getPassword();
        Integer type = loginDTO.getType();

        //1.校验账号密码是否为空
        if (StrUtil.isBlank(account) || StrUtil.isBlank(password) || type == null) {
            throw new BusinessException("你玩蛇皮,账号密码什么都不填,你就就想登陆?");
        }

        //2.校验账号是否存在
        Logininfo logininfo = logininfoMapper.getloginDTO(loginDTO);
        if (logininfo == null) {
            throw new BusinessException("没得你的账号信息啊老表~~~");
        }

        //3.校验密码是否正确
        String md5Pwd = SecureUtil.md5(password + logininfo.getSalt()); //通过MD5加密后的密码
        if (!md5Pwd.equals(logininfo.getPassword())) { //这里取反就是密码是错误的,然后就抛出异常信息
            throw new BusinessException("密码错了啊大哥~~~");
        }
        //4.校验账号状态是否启用
        if (!logininfo.getDisable()) {
            throw new BusinessException("你这账号好像被封了,要不你就问问管理员?~~~");
        }
        //5.登陆成功,保存登陆信息
        //创建一个新的载荷对象,里面存入用户的登陆信息
        Payload payload = new Payload();
        //对敏感数据进行脱敏,不能将密码和盐值返回给前端
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        //将登陆信息存进载荷中
        payload.setLogininfo(logininfo);
        //判断后台登陆的权限和菜单信息,前台的用户是不需要菜单和权限的只有后台用户需要
        if (logininfo.getType() == 0) {
            //查询员工的权限信息
            List<String> permissions = logininfoMapper.getPermissionsByLoginInfoId(logininfo.getId());
            //查询员工的菜单信息
            List<Menu> menus = getMenuTreeLoginInfo(logininfo.getId());
            //将员工的权限信息和员工的菜单信息保存到payload里
            payload.setPermissions(permissions);
            payload.setMenus(menus);
        }
        //6.将用户信息放进jwtToken进行加密处理然后返回给前端
        String token = JwtUtil.generateToken(payload);

        return token;
    }

    private List<Menu> getMenuTreeLoginInfo(Long logininfoId) {
        //查询出菜单信息
        List<Menu> menuList = logininfoMapper.getMenusByLoginInfoId(logininfoId);
        //将这个转换为map
        Map<Long, Menu> map = menuList.stream().collect(Collectors.toMap(Menu::getId, a -> a));
        //定义返回的父类型树,里面是一级类型,子类型都在children集合中
        List<Menu> menuTree = new ArrayList<>();
        for (Menu type : menuList) {
            //如果父类型的id为null那么就是一级类型
            if (type.getParentId() == null) {
                menuTree.add(type); //将这个子类型存进这父类型集合里面
            } else {
                Menu parent = map.get(type.getParentId());
                parent.getChildren().add(type);
            }
        }
        //返回父类型树
        return menuTree;
    }
}
